# coding:utf-8
# writingtime: 2022-7-27
import numpy as np
from random import random
import warnings
from UCI.dataUCI import UCI

warnings.filterwarnings("error")
# v的阈值，用来控制循环是否结束
epsilon = 0.008


class DistanceMeasure:
    @staticmethod
    def euclideandsitance(vector1, vector2):
        """
        :param vector1: 数据向量1
        :param vector2: 数据向量2
        :return: 欧几里得距离
        """
        temp1 = np.array(vector1)
        temp2 = np.array(vector2)
        result = sum((temp1 - temp2) ** 2) ** (1 / 2)
        return result


class FuzzyCMean:
    def __init__(self, dataList, classifications=3):
        """"
        function: 模糊C聚类算法
        :param dataList: 数据集
        :param classifications: 分类的数目
        """
        self.dataList = dataList
        self.classifications = classifications
        self.m = 3
        # 初始化隶属度矩阵
        self.membershipMatrix = self.initialize_membership_matrix()
        # 中心簇初始化
        self.clusterCenter = [list(np.random.random(len(self.dataList[0]))) for _ in range(self.classifications)]
        # self.clusterCenter = [[0.5, 0.5, 0.5, 0.5], [0.5, 0.5, 0.5, 0.5], [0.5, 0.5, 0.5, 0.5]]

    def initialize_membership_matrix(self):
        """
        funcyion 初始化隶属度矩阵(未进行行元素的归一化处理)
        :return: None
        """
        membershipmatrix = []
        for i in range(self.classifications):
            temp = [random() for _ in range(len(self.dataList))]
            temp = [j / sum(temp) for j in temp]
            membershipmatrix.append(temp)
        return membershipmatrix

    def update_cluster(self):
        """
        function: 更新中心簇
        :return: 更新后的中心簇
        """
        new_cluster = []
        for i in range(self.classifications):
            # 计算分母的累加和
            sum_temp = 0
            for k in range(len(self.dataList)):
                sum_temp += self.membershipMatrix[i][k] ** self.m
            # 第i个中心点初始值
            c_temp = np.array([0 for i in range(len(self.dataList[0]))], dtype="float64")
            for j in range(len(self.dataList)):
                temp = np.array(self.dataList[j])
                c_temp += ((self.membershipMatrix[i][j] ** self.m) * temp)
            c_temp = c_temp / sum_temp
            new_cluster.append(list(c_temp))
        return new_cluster

    def update_membership_matrix(self):
        """
        function: 更新隶属度矩阵
        :return: 隶属度矩阵
        """
        new_member_matrix = []
        for i in range(self.classifications):
            li = []
            for j in range(len(self.dataList)):
                # 记录分母的累加和
                sum_temp = 0
                temp1 = DistanceMeasure.euclideandsitance(self.dataList[j], self.clusterCenter[i])
                for k in range(self.classifications):
                    temp2 = DistanceMeasure.euclideandsitance(self.dataList[j], self.clusterCenter[k])
                    # 部分文献在此处是(1/(self.m-1))
                    # sum_temp += 1 / ((temp1 / temp2) ** (2 / (self.m - 1)))
                    # 对分母为0做处理，默认分母为0，累和加0
                    try:
                        # 部分文献在此处是(1/(self.m-1))
                        sum_temp += 1 / ((temp1 / temp2) ** (2 / (self.m - 1)))
                    except RuntimeWarning:
                        # 这样处理的合理性还需要思考
                        # sum_temp += 1 / ((temp1 / temp2) ** (2 / (self.m - 1)))
                        sum_temp += 0
                li.append(sum_temp)
            new_member_matrix.append(li)
        return new_member_matrix

    def getresult(self):
        """
        function: FCM聚类方法，以隶属度差值的最大值小于阈值作为终止条件
        :return:
        """
        flag = True
        while flag:
            old_clustercenter = self.clusterCenter
            # print(old_clustercenter)
            # 更新中心簇
            self.clusterCenter = self.update_cluster()
            # print(self.clusterCenter)
            # print(self.membershipMatrix[0])
            # 更新隶属度矩阵
            self.membershipMatrix = self.update_membership_matrix()
            # print(self.membershipMatrix[0])
            # print(old_clustercenter, '\n', self.clusterCenter, '\n')
            deviationmatrix = [DistanceMeasure.euclideandsitance(old_clustercenter[i], self.clusterCenter[i])
                               for i in range(self.classifications)]
            # print(old_clustercenter, '\n', self.clusterCenter, '\n', max(deviationmatrix), '\n')
            if max(deviationmatrix) < epsilon:
                print(self.clusterCenter)
                print(deviationmatrix)
                flag = False


if __name__ == "__main__":
    data = [[6.1, 2.8, 4.7, 1.2], [5.1, 3.4, 1.5, 0.2], [6.0, 3.4, 4.5, 1.6], [4.6, 3.1, 1.5, 0.2],
            [6.7, 3.3, 5.7, 2.1], [7.2, 3.0, 5.8, 1.6], [6.7, 3.1, 4.4, 1.4], [6.4, 2.7, 5.3, 1.9],
            [4.8, 3.0, 1.4, 0.3], [7.9, 3.8, 6.4, 2.0], [5.2, 3.5, 1.5, 0.2], [5.9, 3.0, 5.1, 1.8],
            [5.7, 2.8, 4.1, 1.3], [6.8, 3.2, 5.9, 2.3], [5.4, 3.4, 1.5, 0.4], [5.4, 3.7, 1.5, 0.2],
            [6.6, 3.0, 4.4, 1.4], [5.1, 3.5, 1.4, 0.2], [6.0, 2.2, 4.0, 1.0], [7.7, 2.8, 6.7, 2.0],
            [6.3, 2.8, 5.1, 1.5], [7.4, 2.8, 6.1, 1.9], [5.5, 4.2, 1.4, 0.2], [5.7, 3.0, 4.2, 1.2]]
    U = [
        [6.1, 2.8], [4.7, 1.2], [5.1, 3.4], [1.5, 0.2],
        [6.7, 3.3], [5.7, 2.1], [7.2, 3.0], [5.8, 1.6],
        [4.8, 3.0], [1.4, 0.3], [7.9, 3.8], [6.4, 2.0],
        [5.7, 2.8], [4.1, 1.3], [6.8, 3.2], [5.9, 2.3],
        [6.6, 3.0], [4.4, 1.4], [5.1, 3.5], [1.4, 0.2],
        [6.3, 2.8], [5.1, 1.5], [7.4, 2.8], [6.1, 1.9],
        [5.5, 2.6], [4.4, 1.2], [5.2, 3.4], [1.4, 0.2],
        [4.6, 3.2], [1.4, 0.2], [5.8, 2.7], [3.9, 1.2]
    ]
    # print(UCI.iris())
    data1=UCI.iris()
    e = FuzzyCMean(data1)
    e.getresult()
    # print(np.random.random(3))
